-- C954026.A
--
--                             Grant of Unlimited Rights
--
--     Under contracts F33600-87-D-0337, F33600-84-D-0280, MDA903-79-C-0687,
--     F08630-91-C-0015, and DCA100-97-D-0025, the U.S. Government obtained 
--     unlimited rights in the software and documentation contained herein.
--     Unlimited rights are defined in DFAR 252.227-7013(a)(19).  By making 
--     this public release, the Government intends to confer upon all 
--     recipients unlimited rights  equal to those held by the Government.  
--     These rights include rights to use, duplicate, release or disclose the 
--     released technical data and computer software in whole or in part, in 
--     any manner and for any purpose whatsoever, and to have or permit others 
--     to do so.
--
--                                    DISCLAIMER
--
--     ALL MATERIALS OR INFORMATION HEREIN RELEASED, MADE AVAILABLE OR
--     DISCLOSED ARE AS IS.  THE GOVERNMENT MAKES NO EXPRESS OR IMPLIED 
--     WARRANTY AS TO ANY MATTER WHATSOEVER, INCLUDING THE CONDITIONS OF THE
--     SOFTWARE, DOCUMENTATION OR OTHER INFORMATION RELEASED, MADE AVAILABLE 
--     OR DISCLOSED, OR THE OWNERSHIP, MERCHANTABILITY, OR FITNESS FOR A
--     PARTICULAR PURPOSE OF SAID MATERIAL.
--*
--
-- OBJECTIVE:
--      Check that if the original protected entry call was a conditional
--      entry call, the call is cancelled if a requeue-with-abort of the 
--      call is not selected immediately.
--      Check that if the original protected entry call was a timed entry 
--      call, the expiration time for a requeue-with-abort is the original 
--      expiration time.
--
-- TEST DESCRIPTION:
--      In this test the main task makes a variety of calls to the protected
--      object Initial_PO.  These calls include a simple call, a conditional 
--      call, and a timed call.  The timed calls include calls with enough
--      time and those with less than the needed amount of time to get through
--      the requeue performed by Initial_PO.
--      Initial_PO requeues its entry call to Final_PO.
--      Final_PO does not accept the requeued call until the protected 
--      procedure Ok_To_Take_Requeue is called.
--      A separate task, Delayed_Opener, is used to call Ok_To_Take_Requeue
--      after a delay amount specified by the main task has expired. 
--
--
-- CHANGE HISTORY:
--      15 DEC 95   SAIC    ACVC 2.1
--      10 JUL 96   SAIC    Incorporated reviewer comments.
--      10 OCT 96   SAIC    Incorporated fix provided by vendor.
--
--!

with Calendar;
use type Calendar.Time;
with Report;
with Impdef;
procedure C954026 is
    Verbose : constant Boolean := False;
    Final_Po_Reached : Boolean := False;
    Allowed_Time : constant Duration := 2.0 * Impdef.One_Long_Second;
    Plenty_Of_Time : constant Duration :=
       Allowed_Time + Impdef.Clear_Ready_Queue + 1.0 * Impdef.One_Long_Second;
    Not_Enough_Time : constant Duration := Allowed_Time - 0.5 * Impdef.One_Long_Second;
begin
    Report.Test ("C954026",
                 "Check that if the original entry" &
                    " call was a conditional or timed entry call," &
                    " the expiration time for a requeue with" &
                    " abort to a protected" &
                    " entry is the original expiration time");
    declare

        protected Initial_Po is
            entry Start_Here;
        end Initial_Po;

        protected Final_Po is
            entry Requeue_Target;
            procedure Ok_To_Take_Requeue;
            procedure Close_Requeue;
        private
            Open : Boolean := False;
        end Final_Po;

        -- the Delayed_Opener task is used to notify Final_PO that it can
        -- accept the Requeue_Target entry.
        task Delayed_Opener is
            entry Start_Timer (Amt : Duration);
            entry Cancel_Timer;
        end Delayed_Opener;

        task body Delayed_Opener is
            Wait_Amt : Duration;
        begin
            loop
                accept Start_Timer (Amt : Duration) do
                    Wait_Amt := Amt;
                end Start_Timer;
                exit when Wait_Amt < 0.0;
                if Verbose then
                    Report.Comment ("Timer started");
                end if;
                select
                    accept Cancel_Timer do
                        Final_Po.Close_Requeue;
                    end Cancel_Timer;   
                or              
                    delay Wait_Amt;
                    Final_Po.Ok_To_Take_Requeue;
                    accept Cancel_Timer do
                        Final_Po.Close_Requeue;
                    end Cancel_Timer;   
                end select;     
            end loop;
        exception
            when others =>
                Report.Failed ("exception in Delayed_Opener");
        end Delayed_Opener;

        protected body Initial_Po is
            entry Start_Here when True is
            begin
                Final_Po_Reached := False;
                requeue Final_Po.Requeue_Target with abort;
            end Start_Here;
        end Initial_Po;

        protected body Final_Po is
            entry Requeue_Target when Open is
            begin
                Open := False;
                Final_Po_Reached := True;
            end Requeue_Target;

            procedure Ok_To_Take_Requeue is
            begin
                Open := True;
            end Ok_To_Take_Requeue;

            procedure Close_Requeue is          
            begin                       
                Open := False;  
            end Close_Requeue;
        end Final_Po;

    begin   -- test encapsulation
        -- unconditional entry call to check the simple case
        Delayed_Opener.Start_Timer (0.0);
        Initial_Po.Start_Here;
        if Final_Po_Reached then
            if Verbose then
                Report.Comment ("simple case passed");
            end if;
        else
            Report.Failed ("simple case");
        end if;
        Delayed_Opener.Cancel_Timer;


        -- timed but with plenty of time - delay relative
        Delayed_Opener.Start_Timer (Allowed_Time);
        select
            Initial_Po.Start_Here;
        or
            delay Plenty_Of_Time;
            Report.Failed ("plenty of time timed out (1)");
            if Final_Po_Reached then
                Report.Failed (
                   "plenty of time timed out after accept (1)");
            end if;
        end select;
        if Final_Po_Reached then
            if Verbose then
                Report.Comment ("plenty of time case passed (1)");
            end if;
        else
            Report.Failed ("plenty of time (1)");
        end if;
        Delayed_Opener.Cancel_Timer;


        -- timed but with plenty of time  -- delay until
        Delayed_Opener.Start_Timer (Allowed_Time);
        select
            Initial_Po.Start_Here;
        or
            delay until Calendar.Clock + Plenty_Of_Time;
            Report.Failed ("plenty of time timed out (2)");
            if Final_Po_Reached then
                Report.Failed (
                  "plenty of time timed out after accept(2)");
            end if;
        end select;
        if Final_Po_Reached then
            if Verbose then
                Report.Comment ("plenty of time case passed (2)");
            end if;
        else
            Report.Failed ("plenty of time (2)");
        end if;
        Delayed_Opener.Cancel_Timer;


        -- timed without enough time - delay relative
        Delayed_Opener.Start_Timer (Allowed_Time);
        select
            Initial_Po.Start_Here;
            Report.Failed ("not enough time completed accept (1)");
        or
            delay Not_Enough_Time;
        end select;
        if Final_Po_Reached then
            Report.Failed ("not enough time (1)");
        else
            if Verbose then
                Report.Comment ("not enough time case passed (1)");
            end if;
        end if;
        Delayed_Opener.Cancel_Timer;


        -- timed without enough time - delay until
        Delayed_Opener.Start_Timer (Allowed_Time);
        select
            Initial_Po.Start_Here;
            Report.Failed ("not enough time completed accept (2)");
        or
            delay until Calendar.Clock + Not_Enough_Time;
        end select;
        if Final_Po_Reached then
            Report.Failed ("not enough time (2)");
        else
            if Verbose then
                Report.Comment ("not enough time case passed (2)");
            end if;
        end if;
        Delayed_Opener.Cancel_Timer;


        -- conditional case
        Delayed_Opener.Start_Timer (Allowed_Time);
        select
            Initial_Po.Start_Here;
            Report.Failed ("no time completed accept");
        else
            if Verbose then
                Report.Comment ("conditional case - else taken");
            end if;
        end select;
        if Final_Po_Reached then
            Report.Failed ("no time");
        else
            if Verbose then
                Report.Comment ("no time case passed");
            end if;
        end if;
        Delayed_Opener.Cancel_Timer;

        -- kill off the Delayed_Opener task
        Delayed_Opener.Start_Timer (-10.0);

    exception
        when others =>
            Report.Failed ("exception in main");
    end;

    Report.Result;
end C954026;
